﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Carrot.Core.Logging
{
    /// <summary>
    /// An extension of <see cref="ILogger"/> that helps to ease to do log with specific log level.
    /// </summary>
    public static class LoggerExtension
    {
        #region Debug log overloading
        /// <summary>
        /// Logs debugging information with static message
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="message">Debugging message</param>
        public static void Debug(this ILogger logger, string message)
        {
            FilteredLog(logger, LogLevel.Debug, null, null, message, null);
        }

        /// <summary>
        /// Logs static debugging message including exception information
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">An exception occurred</param>
        /// <param name="message">Debugging message</param>
        public static void Debug(this ILogger logger, Exception exception, string message)
        {
            FilteredLog(logger, LogLevel.Debug, exception, null, message, null);
        }

        /// <summary>
        /// Logs formatting debugging message
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="format">A formatting message</param>
        /// <param name="parameters">Passed values to formatting message</param>
        public static void Debug(this ILogger logger, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Debug, null, null, format, parameters);
        }

        /// <summary>
        /// Logs formatting debugging message including exception information
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">A occurred exception</param>
        /// <param name="format">The formatting string of the message</param>
        /// <param name="parameters">Passed values to formatting string</param>
        public static void Debug(this ILogger logger, Exception exception, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Debug, exception, null, format, parameters);
        }

        /// <summary>
        /// Logs formatting debugging message including exception information
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">A occurred exception</param>
        /// <param name="formatProvider">The format provider</param>
        /// <param name="format">The formatting string of the message</param>
        /// <param name="parameters">Passed values to formatting string</param>
        public static void Debug(this ILogger logger, Exception exception, IFormatProvider formatProvider, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Debug, exception, formatProvider, format, parameters);
        }

        #endregion

        #region Information logs overloading

        /// <summary>
        /// Logs information of running process with static message
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="message">Information message</param>
        public static void Information(this ILogger logger, string message)
        {
            FilteredLog(logger, LogLevel.Information, null, null, message, null);
        }

        /// <summary>
        /// Logs static information message including exception information.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">An exception occurred</param>
        /// <param name="message">Information message</param>
        public static void Information(this ILogger logger, Exception exception, string message)
        {
            FilteredLog(logger, LogLevel.Information, exception, null, message, null);
        }

        /// <summary>
        /// Logs formatting information message.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="format">A formatting message</param>
        /// <param name="parameters">Passed values to formatting message</param>
        public static void Information(this ILogger logger, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Information, null, null, format, parameters);
        }

        /// <summary>
        /// Logs formatting information message including exception information.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">A occurred exception</param>
        /// <param name="format">The formatting string of the message</param>
        /// <param name="parameters">Passed values to formatting string</param>
        public static void Information(this ILogger logger, Exception exception, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Information, exception, null, format, parameters);
        }

        /// <summary>
        /// Logs formatting information message including exception information.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">A occurred exception</param>
        /// <param name="formatProvider">The format provider</param>
        /// <param name="format">The formatting string of the message</param>
        /// <param name="parameters">Passed values to formatting string</param>
        public static void Information(this ILogger logger, Exception exception, IFormatProvider formatProvider, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Information, exception, formatProvider, format, parameters);
        }

        #endregion

        #region Logs with formatting message

        /// <summary>
        /// Logs static warning message when system found any unexpected behaviours inside.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="message">Waring message</param>
        public static void Warning(this ILogger logger, string message)
        {
            FilteredLog(logger, LogLevel.Warning, null, null, message, null);
        }

        /// <summary>
        /// Logs formatting warning message.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="format">A formatting message</param>
        /// <param name="parameters">Passed values to formatting message</param>
        public static void Warning(this ILogger logger, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Warning, null, null, format, parameters);
        }

        /// <summary>
        /// Logs warning message including exception information.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">An exception occurred</param>
        /// <param name="message">Warning message</param>
        public static void Warning(this ILogger logger, Exception exception, string message)
        {
            FilteredLog(logger, LogLevel.Warning, exception, null, message, null);
        }

        /// <summary>
        /// Logs formatting warning message including exception information.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">A occurred exception</param>
        /// <param name="format">The formatting string of the message</param>
        /// <param name="parameters">Passed values to formatting string</param>
        public static void Warning(this ILogger logger, Exception exception, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Warning, exception, null, format, parameters);
        }

        /// <summary>
        /// Logs formatting warning message including exception information.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">A occurred exception</param>
        /// <param name="formatProvider">The format provider</param>
        /// <param name="format">The formatting string of the message</param>
        /// <param name="parameters">Passed values to formatting string</param>
        public static void Warning(this ILogger logger, Exception exception, IFormatProvider formatProvider, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Warning, exception, formatProvider, format, parameters);
        }

        #endregion

        #region Error log overloading

        /// <summary>
        /// Logs static error message when an exception occurs.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="message">Error message</param>
        public static void Error(this ILogger logger, string message)
        {
            FilteredLog(logger, LogLevel.Error, null, null, message, null);
        }

        /// <summary>
        /// Logs error message including exception infomration.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">An exception occurred</param>
        /// <param name="message">Error message</param>
        public static void Error(this ILogger logger, Exception exception, string message)
        {
            FilteredLog(logger, LogLevel.Error, exception, null, message, null);
        }

        /// <summary>
        /// Logs formatting error message.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="format">A formatting message</param>
        /// <param name="parameters">Passed values to formatting message</param>
        public static void Error(this ILogger logger, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Error, null, null, format, parameters);
        }

        /// <summary>
        /// Logs formatting error message including exception information.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">A occurred exception</param>
        /// <param name="format">The formatting string of the message</param>
        /// <param name="parameters">Passed values to formatting string</param>
        public static void Error(this ILogger logger, Exception exception, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Error, exception, null, format, parameters);
        }

        /// <summary>
        /// Logs formatting error message including exception information.
        /// </summary>
        /// <param name="logger">An instance of <see cref="ILogger"/></param>
        /// <param name="exception">A occurred exception</param>
        /// <param name="formatProvider">The format provider</param>
        /// <param name="format">The formatting string of the message</param>
        /// <param name="parameters">Passed values to formatting string</param>
        public static void Error(this ILogger logger, Exception exception, IFormatProvider formatProvider, string format, params object[] parameters)
        {
            FilteredLog(logger, LogLevel.Error, exception, null, format, parameters);
        }

        #endregion

        private static void FilteredLog(ILogger logger, LogLevel level, Exception exception, IFormatProvider formatProvider, string format, params object[] parameters)
        {
            if (logger.IsEnabled(level))
            {
                logger.Log(level, exception, formatProvider, format, parameters);
            }
        }

        
    }
}
